using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading;
using OpenCvTesting.CallibrationWizard;
using OpenCvTesting.PerformanceTester;

namespace OpenCvTesting
{
	public partial class mainFrame : Form
	{
		#region Fields
		Thread cameraCaptureThread;
		StethLocationData locationData = new StethLocationData();

		Pen stethLocationPen = new Pen(Color.Red);
		#endregion

		#region Constructors
		public mainFrame()
		{
			InitializeComponent();
		}
		#endregion

		#region Delegates
		delegate void DisplayPushedImageDelegate(byte[] imageData, int width, int height, PictureBox picBox);
		#endregion

		#region UI event handlers
		private void btnStartCapturing_Click(object sender, EventArgs e)
		{
			cameraCaptureThread = new Thread(new ThreadStart(StartCapturingFromCamera));
			cameraCaptureThread.Start();
		}

		private void btnStartCapturingFromFile_Click(object sender, EventArgs e)
		{
			cameraCaptureThread = new Thread(new ThreadStart(StartCapturingFromFile));
			cameraCaptureThread.Start();
		}

		private void btnCaptureFromCamWithRecording_Click(object sender, EventArgs e)
		{
			SaveFileDialog saveFileDlg = new SaveFileDialog();
			saveFileDlg.Filter = "avi files|*.avi";
			if (saveFileDlg.ShowDialog() == DialogResult.OK)
			{
				cameraCaptureThread = new Thread(new ParameterizedThreadStart(StartCapturingFromCameraAndRecord));
				cameraCaptureThread.Start(saveFileDlg.FileName);
			}
		}

		private void Form1_FormClosing(object sender, FormClosingEventArgs e)
		{
			OpenCvAdapterNativeMethods.StopCapturing();
		}

		private void btnStopCapturing_Click(object sender, EventArgs e)
		{
			OpenCvAdapterNativeMethods.StopCapturing();
		}

		private void btnCalibrate_Click(object sender, EventArgs e)
		{
			CallibrationWizardDialog wizard = new CallibrationWizardDialog();
			wizard.ShowDialog();
		}

		private void btnTest_Click(object sender, EventArgs e)
		{
			OpenCvAdapterNativeMethods.StartProcessing();
		}

		private void pictureBox1_Paint(object sender, PaintEventArgs e)
		{
			Graphics g = e.Graphics;
			g.TranslateTransform(150, 50);
			int width = 5;
			PointF p = new PointF(0, 0);
			lock(this.locationData)
			{
				p = StethLocationDataManipulator.GetMappedStethLocation(this.locationData);
			}
			g.DrawRectangle(stethLocationPen, p.X - width / 2, p.Y + width / 2, width, width);
		}

		private void btnFileOpen_Click(object sender, EventArgs e)
		{
			OpenFileDialog fileOpenDlg = new OpenFileDialog();
			fileOpenDlg.Filter = "Avi Files|*.avi";
			if (fileOpenDlg.ShowDialog() == DialogResult.OK)
			{
				this.txtFileName.Text = fileOpenDlg.FileName;
			}
		}

		private void btnPerformance_Click(object sender, EventArgs e)
		{
			PerformanceTesterDlg performanceTesterDlg = new PerformanceTesterDlg();
			performanceTesterDlg.ShowDialog();
		}

		#endregion

		#region Private methods
		private void StartCapturingFromCamera()
		{
			OpenCvAdapterNativeMethods.StartCapturing(new OpenCvAdapterNativeMethods.ImagePushedDelegate(SourceImagePushed),
				new OpenCvAdapterNativeMethods.StethLocationDataPushedDelegate(LocationDataPushed));
		}

		private void StartCapturingFromFile()
		{
			StringBuilder builder = new StringBuilder(this.txtFileName.Text);
			OpenCvAdapterNativeMethods.StartCapturingFromFile(builder,
				new OpenCvAdapterNativeMethods.ImagePushedDelegate(SourceImagePushed),
				new OpenCvAdapterNativeMethods.StethLocationDataPushedDelegate(LocationDataPushed),
				new OpenCvAdapterNativeMethods.CapturingFinishedDelegate(CapturingFinished));
		}

		private void StartCapturingFromCameraAndRecord(object fileName)
		{
			{
				StringBuilder builder = new StringBuilder(fileName.ToString());
				OpenCvAdapterNativeMethods.StartCaptureAndRecord(builder,
					new OpenCvAdapterNativeMethods.ImagePushedDelegate(SourceImagePushed),
					new OpenCvAdapterNativeMethods.StethLocationDataPushedDelegate(LocationDataPushed));
			}
		}
		
		private void SourceImagePushed(int width, int height, IntPtr imageDataPointer)
		{
			DisplayPushedImageOnControl(width, height, imageDataPointer, this.picBoxSource);
		}

		private void LocationDataPushed(IntPtr locationDataPtr)
		{
			StethLocationData locationData = new StethLocationData();
			Marshal.PtrToStructure(locationDataPtr, locationData);
			lock (this.locationData)
			{
				this.locationData = locationData;
			}
		}

		private void CapturingFinished()
		{
			//do nothing
		}

		private void DisplayPushedImageOnControl(int width, int height, IntPtr imageDataPointer, PictureBox picBox)
		{
			int size = height * width;
			byte[] imageData = new byte[size];
			Marshal.Copy(imageDataPointer, imageData, 0, size);
			if (picBox.InvokeRequired)
			{
				picBox.BeginInvoke(new DisplayPushedImageDelegate(DisplayPushedImage), imageData, width, height, picBox);
			}
			else
			{
				DisplayPushedImage(imageData, width, height, picBox);
			}
		}

		private void DisplayPushedImage(byte[] imageData, int width, int height, PictureBox picBox)
		{
			this.picBoxSource.Image = BitmapCreationHelper.GetBitmapFromPixelData(imageData, width, height);
			this.picBoxSource.Refresh();
			this.pictureBox1.Refresh();
		}
		#endregion
	}
}